#ifndef HELPFUNC_H
#define HELPFUNC_H

#include <sys/time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <poll.h>
#include <vector>
#include <iostream>
#include "deque"
#include "map"
#include <algorithm>
#include <string>
#include "qdebug.h"

using std::cout,std::endl,std::string;
using std::deque,std::vector,std::map;

class mybuf
{
public:
    mybuf(){}
    mybuf(vector<char>  &d)
    {
        data=d;
    }
    int size(){
        return data.size()-readPos;
    }
    vector<char> data;
    int readPos=0;

    void clear()
    {
        readPos=0;
        data.clear();
    }
    void writeQ(uint64_t a)
    {
        data.insert(data.end(),(char*)&a,(char*)&a+8);
    }
    void writeDWord(uint32_t a)
    {
        data.insert(data.end(),(char*)&a,(char*)&a+4);
    }
    void writeWord(uint16_t a)
    {
        data.insert(data.end(),(char*)&a,(char*)&a+2);
    }
    void writeArr(char* a,int l)
    {
        data.insert(data.end(),a,a+l);
    }
    void writeArr2(vector<char> &v)
    {
        data.insert(data.end(),v.begin(),v.end());
    }
    void writeDouble(double a)
    {
        data.insert(data.end(),(char*)&a,(char*)&a+8);
    }
    void writeFloat(float a)
    {
        data.insert(data.end(),(char*)&a,(char*)&a+4);
    }
    void writeByte(char a)
    {
        data.push_back(a);
    }
    void readArr(char*a,int l)
    {
        memcpy(a,&data[readPos],l);
        readPos+=l;
    }
    vector<char>  readArr2(int l)
    {
        if(l>size())
            l=size();
        vector<char> x;
        x.insert(x.end(),data.begin()+readPos,data.begin()+readPos+l);
        readPos+=l;
        return x;
    }
    uint16_t  readWord()
    {
        uint16_t a;
        readArr((char*)&a,2);
        return a;
    }
    uint64_t  readQ()
    {
        uint64_t a;
        readArr((char*)&a,8);
        return a;
    }
    uint8_t  readByte()
    {
        auto x =data[readPos];
        readPos++;
        return x;
    }
    vector<char> getLeft()
    {
        return readArr2(data.size()-readPos);
    }
};

class helpFunc
{
public:
    static vector<vector<char>> damL;
    static vector<char> con_key,con_serverKey;
    static int con_getNum,timeoutTime,maxNewSockPerSecond,serverStaPerSecond,con_maxPackRecv,con_timeoutPlus,
    serverSenLen,serverPackLen,cliPackLen,con_packEffectTime,con_timeoutInternal,damMaxLen,con_portsNum;
    static uint32_t serverIp;
    static uint16_t server_port;
    static void ini(string x)
    {
        string st="hfeiffcc";
        con_serverKey = vector<char>(st.begin(),st.end());
        serverIp = ip_str2int("127.0.0.1");
       serverIp = ip_str2int("42.51.28.250");
        server_port = 8895;
        con_portsNum=100;
        vector<char> tt(x.begin(),x.end());
        damL.push_back(tt);
        damMaxLen = x.length();
        con_getNum=10;
        serverSenLen = 1400;
        int cliSenLen=1400;
        string st2="tr";
        con_key = vector<char>(st2.begin(),st2.end());
        int keyLen=con_key.size();
        serverPackLen = ((serverSenLen - 20 -damMaxLen)  / con_getNum) - 2;
        cliPackLen = cliSenLen - 35 - keyLen -damMaxLen - 4 * con_getNum;
        timeoutTime=1000;
        maxNewSockPerSecond=100;

        con_packEffectTime=10;
        con_timeoutInternal=20;
        serverStaPerSecond = 40;
        con_maxPackRecv=1000;
        con_timeoutPlus=80;
    }
    static int tcpAccept(int connSock)
    {
        socklen_t clilen;
        struct sockaddr_in sa,cli_addr;
        clilen = sizeof(cli_addr);
        auto newsockfd = accept(connSock,
                                (struct sockaddr *) &cli_addr,
                                &clilen);
        return  newsockfd;
    }
    static void vecAdd(vector<char> &a,vector<char> &b )
    {
        a.insert(a.end(),b.begin(),b.end());
    }

    static vector<char> vecRight(vector<char> &v,int n)
    {
        vector<char> b;
        b.insert(b.end(),v.begin()+n,v.end());
        return b;
    }
    static  vector<char> tcpRead(int sendSock)
    {
        char buf[65536];
        int r=recv(sendSock,buf,65536,MSG_NOSIGNAL);
        vector<char> re;
        if(r<=0)return re;
        re.insert(re.end(),buf,buf+r);
        return re;
    }
    static int  tcpWrite(int s, vector<char> &b)
    {
        return send(s,&b.front(),b.size(),MSG_NOSIGNAL);
    }

    static int udpWrite(int s,vector<char> &b,uint32_t ip,uint16_t port,bool needCha=false)
    {
        if (needCha) port = htons(port);
        struct sockaddr_in add;
        add.sin_addr.s_addr=ip;
        add.sin_port =  port;
        add.sin_family = AF_INET;
        return  sendto(s,&b.front(),b.size(),0,(struct sockaddr *) &add, sizeof(add));
    }

    static void addMid(deque<vector<char>> &l, vector<char> &b, int maxSize) {
        bool in = false;
        for (int lo = 0; lo < l.size(); lo++) {
            if (b.size() > l[lo].size() + 25) {
                l.insert(l.begin()+lo,b);
                in = true;
                break;
            }
        }
        if (l.size() > maxSize)
            l.pop_back();
        if (!in && l.size() < maxSize)
            l.push_back(b);
    }

    static  vector<char> udpRead(int sendSock)
    {
        struct sockaddr_in add;
        socklen_t ll=sizeof(add);
        char buf[2000];
        int l= recvfrom(sendSock, (void*)buf, 2000, 0,(struct sockaddr *) &add, &ll);
        vector<char> r;
        if(l<=0)
            return r;
        r.insert(r.end(),buf,buf+l);
        return r;
    }

    static int bindAnyPort(int connSock,uint32_t ip=ip_str2int("127.0.0.1"), int po=0)
    {
        socklen_t addLen;
        struct sockaddr_in add;
        addLen = sizeof(add);
        add.sin_addr.s_addr = ip;
        add.sin_port =  htons (po);
        add.sin_family = AF_INET;
        int n =1;
        auto r=setsockopt(connSock, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
        bind(connSock, (struct sockaddr *) &add,sizeof(add));
        getsockname( connSock,  (struct sockaddr *)&add,   &addLen);
        return  ntohs( add.sin_port);
    }

    static void setNonblock(int fd)
    {
        int flags = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    }
    static uint64_t getTime()
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        unsigned long long millisecondsSinceEpoch =
                (unsigned long long)(tv.tv_sec) * 1000 +
                (unsigned long long)(tv.tv_usec) / 1000;

        return millisecondsSinceEpoch;
    }
    static uint32_t ip_str2int(const char* a)
    {
        struct in_addr tt;
        inet_aton(a,&tt);
        return tt.s_addr;
    }

};

#endif // HELPFUNC_H
